package com.ruoyi.system.controller;

import com.alibaba.fastjson.JSON;
import com.ruoyi.common.core.constant.ActivityConstant;
import com.ruoyi.common.core.constant.Constants;
import com.ruoyi.common.core.utils.DateUtils;
import com.ruoyi.common.core.utils.RegExUtil;
import com.ruoyi.common.core.utils.uuid.IdUtils;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.system.domain.Activity;
import com.ruoyi.system.domain.vo.ActivityVo;
import com.ruoyi.system.domain.vo.ApproveVo;
import com.ruoyi.system.service.IActivityService;
import org.redisson.api.RSemaphore;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.TriggerContext;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Date;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ScheduledFuture;


@Transactional(rollbackFor = Exception.class)
@RestController
@RequestMapping("/schedule")
public class ScheduleController {


    @Autowired
    IActivityService activityService;

    @Autowired
    private ThreadPoolTaskScheduler threadPoolTaskScheduler;

    @Autowired
    RabbitTemplate rabbitTemplate;

    @Autowired
    RedisTemplate<String,String> redisTemplate;

    @Autowired
    RedissonClient redissonClient;



    /*
    * TODO:
    *   修改活动状态为发布状态,将数据存储到redis里面
    *   开启定时任务,到报名时间,修改活动状态为报名状态,将活动存放mq里
    *   mq过时后,修改活动状态为终止报名状态
    *
    * 抢活动(报名)逻辑(不在这个controller里写):
    * 从redis里取出数据,然后放到报名锁定表里,等待最终录取
    * 录取成功后,将锁定表的数据删除,然后存到报名表里
    *
    * */

    @PostMapping("/publishActivity/{id}")
    public AjaxResult publishActivity(@PathVariable("id")String id){

        if (!RegExUtil.isNumber(id)){
            return AjaxResult.error("id必须是数字");
        }

        Activity activity = activityService.selectActivityById(Long.parseLong(id));
        if (activity==null){
            return AjaxResult.error("活动不存在,无法发布!");
        }
        if (!activity.getStatus().equals(ActivityConstant.APPROVE_FINAL)){
            return AjaxResult.error("活动未审核成功!");
        }
        Date signupTime = activity.getSignupTime();
        Date nowDate = DateUtils.getNowDate();

        if (DateUtils.compareDate(nowDate,signupTime)==1){
            return AjaxResult.error("该活动已过报名时间");
        }

        //修改活动状态为发布状态
        Activity publishActivity = new Activity();
        publishActivity.setId(activity.getId());
        publishActivity.setStatus(ActivityConstant.PUBLISH_STATUS);
        activityService.updateActivity(publishActivity);

        threadPoolTaskScheduler.schedule(new Runnable() {
            @Override
            public void run() {
                //到时间修改活动状态为报名状态
                Activity activityNew = new Activity();
                activityNew.setId(activity.getId());
                activityNew.setStatus(ActivityConstant.SINGUP_STATUS);
                activityService.updateActivity(activityNew);
                //将信息存在redis中
                ActivityVo activityVo = new ActivityVo();
                String uuid = IdUtils.fastUUID();
                activityVo.setCheckCode(uuid);
                BeanUtils.copyProperties(activityNew ,activityVo);
                HashOperations<String, String, String> hash = redisTemplate.opsForHash();
                hash.put("activity::skill",id,JSON.toJSONString(activityVo));
                //设置信号量,活动的报名数量
                RSemaphore semaphore = redissonClient.getSemaphore("activity::skill::" + uuid);
                semaphore.trySetPermits(activity.getSignupCount().intValue());

                //活动开始前五分钟,报名时间结束
                long l = activity.getStartTime().getTime() - activity.getSignupTime().getTime()- Constants.BEFORE_STARTER*60*1000;
                threadPoolTaskScheduler.schedule(new Runnable() {
                    @Override
                    public void run() {
                        Activity activityLast = new Activity();
                        activityLast.setId(activity.getId());
                        activityLast.setStatus(ActivityConstant.SINGUP_FINAL);
                        activityService.updateActivity(activityLast);
                        //删除redis的数据
                        hash.delete("activity::skill",id);
                    }
                },new Date(activity.getSignupTime().getTime()+l));

                //活动开始后,无法进行报名表的录取操作
                threadPoolTaskScheduler.schedule(new Runnable() {
                    @Override
                    public void run() {
                        //删除redis里的报名表
                        redisTemplate.delete(activity.getId()+"::isSkill");

                    }
                },activity.getStartTime());
            }
        },activity.getSignupTime());

        threadPoolTaskScheduler.schedule(new Runnable() {
            @Override
            public void run() {
                //活动开启
                Activity activityStart = new Activity();
                activityStart.setId(activity.getId());
                activityStart.setStatus(ActivityConstant.STARTING_STATUS);
                activityService.updateActivity(activityStart);
                //规定时间活动结束
                threadPoolTaskScheduler.schedule(new Runnable() {
                    @Override
                    public void run() {
                        Activity activityLasted = new Activity();
                        activityLasted.setId(activity.getId());
                        activityLasted.setStatus(ActivityConstant.LASTED_STATUS);
                    }
                },activity.getLastTime());
            }
        },activity.getStartTime());

        return AjaxResult.success();
    }

}
